#include "ShaderManager.h"
#include "D3D9Renderer.h"
#include "Mesh.h"
#include "Material.h"
#include "../Utility/Misc/DebugOutput.h"

ID3DXEffect*	ShaderManager::basicEffect = 0;
ID3DXEffect*	ShaderManager::unlitColor = 0;
ID3DXEffect*	ShaderManager::unlitColorOrtho = 0;

//Camera handles
D3DXHANDLE		ShaderManager::hMVP;
D3DXHANDLE		ShaderManager::hOrtho;

// Color handle
D3DXHANDLE		ShaderManager::hColor;

//Texture handles
D3DXHANDLE		ShaderManager::hDiffuse;
D3DXHANDLE		ShaderManager::hNormal;
D3DXHANDLE		ShaderManager::hSpecular;

XMMATRIX		ShaderManager::ortho;

void ShaderManager::Initialize()
{
	LoadShaders();
	LoadHandles();
}

void ShaderManager::Shutdown()
{
	if(basicEffect)
	{
		basicEffect->Release();
		basicEffect = 0;
	}

	if(unlitColor)
	{
		unlitColor->Release();
		unlitColor = 0;
	}

	if(unlitColorOrtho)
	{
		unlitColorOrtho->Release();
		unlitColorOrtho = 0;
	}
}

void ShaderManager::LoadShaders()
{
	ID3DXBuffer* errors(NULL);
	D3DXCreateEffectFromFile(D3D9Renderer::device, "Res/Shaders/basic.fx", 0, 0, D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION, D3D9Renderer::effectPool, &basicEffect, &errors);

	if(errors)
	{
#ifdef _DEBUG
		DebugOutput::Print(DebugOutput::RENDER_MSG, DebugOutput::FAILURE_SHADER_COMPILE, (char*)errors->GetBufferPointer());
#endif
	}

	errors = NULL;
	D3DXCreateEffectFromFile(D3D9Renderer::device, "Res/Shaders/color.fx", 0, 0, D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION, D3D9Renderer::effectPool, &unlitColor, &errors);

	if(errors)
	{
#ifdef _DEBUG
		DebugOutput::Print(DebugOutput::RENDER_MSG, DebugOutput::FAILURE_SHADER_COMPILE, (char*)errors->GetBufferPointer());
#endif
	}

	errors = NULL;
	D3DXCreateEffectFromFile(D3D9Renderer::device, "Res/Shaders/colorOrtho.fx", 0, 0, D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION, D3D9Renderer::effectPool, &unlitColorOrtho, &errors);

	if(errors)
	{
#ifdef _DEBUG
		DebugOutput::Print(DebugOutput::RENDER_MSG, DebugOutput::FAILURE_SHADER_COMPILE, (char*)errors->GetBufferPointer());
#endif
	}
}

void ShaderManager::LoadHandles()
{
	hMVP		= basicEffect->GetParameterByName(0,"MVP");
	hOrtho		= unlitColorOrtho->GetParameterByName(0, "Ortho");
	hColor		= unlitColor->GetParameterByName(0,"geometryColor");
	hDiffuse	= basicEffect->GetParameterByName(0,"diffuseMap");
	hNormal;
	hSpecular;
}

void ShaderManager::RenderColorIndexed(Mesh &mesh, Material& material)
{
	unlitColor->SetTechnique("basicShader");
	unlitColor->SetValue(hColor, material.color, sizeof(float)*4);
	unlitColor->CommitChanges();

	unsigned int passes = 0;

	unlitColor->Begin(&passes, 0);

	for(unsigned int i = 0; i<passes; ++i)
	{
		unlitColor->BeginPass(i);

		D3D9Renderer::device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,mesh.startVertex, 0, mesh.vertCount, mesh.startIndex, mesh.primitiveCount);

		unlitColor->EndPass();
	}

	unlitColor->End();
}

void ShaderManager::RenderColorOrtho(Mesh& mesh, Material& material)
{
	unlitColorOrtho->SetTechnique("basicShader");
	unlitColorOrtho->SetValue(hColor, material.color, sizeof(float)*4);
	unlitColorOrtho->CommitChanges();

	unsigned int passes = 0;

	unlitColorOrtho->Begin(&passes, 0);

	for(unsigned int i = 0; i<passes; ++i)
	{
		unlitColorOrtho->BeginPass(i);

		D3D9Renderer::device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,mesh.startVertex, 0, mesh.vertCount, mesh.startIndex, mesh.primitiveCount);

		unlitColorOrtho->EndPass();
	}

	unlitColorOrtho->End();
}

void ShaderManager::RenderDiffuseIndexed(Mesh& mesh, Material& material)
{
	basicEffect->SetTechnique("basicShader");

	basicEffect->CommitChanges();

	unsigned int passes = 0;

	basicEffect->Begin(&passes, 0);

	for(unsigned int i = 0; i<passes; ++i)
	{
		basicEffect->BeginPass(i);

		D3D9Renderer::device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,mesh.startVertex, 0, mesh.vertCount, mesh.startIndex, mesh.primitiveCount);

		basicEffect->EndPass();
	}

	basicEffect->End();
}

XMMATRIX ShaderManager::GetOrtho()
{
	return XMMatrixOrthographicOffCenterRH(0.0f,1.0f,0.0f,1.0f,0.0f,1.0f);
}

void ShaderManager::SetMVP(XMMATRIX& _mvp)
{ 
	basicEffect->SetValue(hMVP, &_mvp, sizeof(_mvp));
}

void ShaderManager::SetOrtho(XMMATRIX& _ortho)
{ 
	unlitColorOrtho->SetValue(hOrtho, &_ortho, sizeof(_ortho));
}

void ShaderManager::SetMaterialDiffuse(Material& material)
{
	basicEffect->SetTexture(hDiffuse, material.diffuseMap);
}